dojo.provide("xray.PreviewChart");

dojo.require("dojox.charting.Chart2D");
dojo.require("dojox.charting.themes.ET.greys");

dojo.require("dojox.lang.functional");
dojo.require("dojox.lang.functional.fold");

dojo.declare(
	"xray.PreviewChart",
	null,
	{
		constructor:function(data){
			this.data = data;
			this.MEM_SERIES = 0,
			this.CPU_SERIES = 1;
			//this.NETWORK_TRAFFIC_SERIES = 2;
			this.CHART_WIDTH = 4*60; // The number of slots on the x-axis.
			this.RESOLUTION = 100; // The resolution of one slot on the x-axis, in milliseconds.
			this.DRAW_INTERVAL = 1000; // Every how many milliseconds shall the chart be redrawn?
			
			// It stores the drawn series for the next draw we only have to add
			// the missing pieces. The series is stored in reverse!!!
			this.series = s = [[], []];
			for (var i=0, len=this.CHART_WIDTH*this.RESOLUTION; i<len; i++){
				s[this.MEM_SERIES].push(0);
				s[this.CPU_SERIES].push(0);
			}
		},
		
		create:function(){
			var s = [[], []];
			for (var i=0; i<this.CHART_WIDTH; i++){
				s[this.MEM_SERIES] = 0;
				s[this.CPU_SERIES] = 0;
			}
			this.chart = new dojox.charting.Chart2D("smallGraphContent");
			this.chart.setTheme(dojox.charting.themes.ET.greys);
			
			this.chart.addAxis("x", {majorLabels: false, fixLower:"minor", natural:true, min:1, max:this.CHART_WIDTH});
			this.chart.addAxis("y", {majorLabels: false, vertical: true, min: 0, max: 500});
		//	this.chart.addPlot("default", {type: "Lines"});
			
		//	this.chart.addSeries("memory", s[this.MEM_SERIES], {stroke:{width:2, color:"#73d9ef"}});
		//	this.chart.addPlot("grid", {type: "Grid", hMinorLines: true});

		//	this.chart.addAxis("y2", {majorLabels: false, vertical: true, min: 0, max: 100, majorTickStep: 100, minorTickStep: 100, leftBottom: false});
		//	this.chart.addPlot("cpuPlot", {type: "Lines", hAxis: "x", vAxis: "y2"});
		//	this.chart.addSeries("cpu", s[this.CPU_SERIES], {stroke:{width:2, color:"#b1e182"}, plot: "cpuPlot"});
			
			// The event lines
			//chart.addAxis("yPageEvent", {vertical: true, fixLower: "major", fixUpper: "major", natural: true, min:0, max:1});
			//chart.addPlot("pageEventPlot", {type: "Bars"});
			//chart.addSeries("pageEvent", [0,1,0,0,1,0,0,1], {stroke:{width:1, color:"red"}, plot: "pageEventPlot"});
			
			this.chart.render();
			//setInterval(dojo.hitch(this, "draw"), this.DRAW_INTERVAL);
		},
		
		lastTimestampInSeries:0,
		draw:function(){
			var df = dojox.lang.functional;
			var now = new Date().getTime()
			var s = this.series;
			if (this.lastTimestampInSeries == 0){
				var d = this.data.get(now - this.CHART_WIDTH * this.RESOLUTION);
				// on startup we might not have any data
				if (!d){
					return;
				}
				this.lastTimestampInSeries = d[0].timestamp;
			}else{
				var d = this.data.get(this.lastTimestampInSeries);
			}
//console.log("d.length=", d.length, "this.lastTimestampInSeries=", this.lastTimestampInSeries);
			// Prepare the data for the series.
			// Get the data and build an index by timestamp.
//console.log(dojo.toJson(d));
			var timestampToDataMap = {};
			for (var i=0; i<d.length; i++){
				timestampToDataMap[d[i].timestamp] = d[i];
			}
			
			var lastData = d[d.length-1];
			// The timestamp when the data were last pushed into the series.
			var lastTimestamp = now;
			// Collect the data in dataPoint until we can push them into a series' data point, which will
			// only get the average of the collected data.
			var dataPoint = [[], []]; // mem, cpu
			// Fill the array form the end, until we reached CHART_WIDTH.
//console.log("draw");
//console.log(dojo.toJson(d));
//console.log("lastData", dojo.toJson(lastData));
			for (var ms=now; ms > this.lastTimestampInSeries; ms--){
//console.log(1, ms);
				// Update the lastData, if there are data in this.data for the
				// current timestamp, this makes sure that always the newest,
				// latest value is stored in lastData, relative to ms!
				// Which means if ms=10 the data for the closest timestamp that is SMALLER
				// are contained in lastData.
				if (timestampToDataMap[ms]){
					lastData = timestampToDataMap[ms];
//console.log(ms, "update lastData", dojo.toJson(lastData), lastTimestamp-ms);

					// publish data change
					dojo.publish("/xray/memChange", [lastData.memory]);
					dojo.publish("/xray/cpuChange", [lastData.cpu]);
				}
//console.log(2, lastData);
				if (lastTimestamp - ms < this.RESOLUTION){
//console.log("+dataPoint", dataPoint[this.MEM_SERIES].length);
					if (ms==lastData.timestamp){
						dataPoint[this.MEM_SERIES].push(+lastData.memory);
						dataPoint[this.CPU_SERIES].push(+lastData.cpu);
//console.log(3, dataPoint[0].length);
					}
				}else{
					var dp = dataPoint[this.MEM_SERIES].length ? dataPoint[this.MEM_SERIES] : [lastData.memory];
//console.log(4, dojo.toJson(dp), df.reduce(dp, function(a, b){return a+b}) / dp.length);
//console.log("push", s[this.MEM_SERIES].length);
					// Make it mega bytes (divide by 1024).
//console.log("dataPoint, before pushing:", dojo.toJson(dp));
					s[this.MEM_SERIES].push((df.reduce(dp, function(a, b){return a+b}) / dp.length)/1024);
					dp = dataPoint[this.CPU_SERIES].length ? dataPoint[this.CPU_SERIES] : [lastData.cpu];
//console.log(4.1, dojo.toJson(dp), df.reduce(dp, function(a, b){return a+b}));
					s[this.CPU_SERIES].push(df.reduce(dp, function(a, b){return a+b}) / dp.length);
					dataPoint = [[], []];
					lastTimestamp = ms;
				}
			}
			// If we have someting stored dataPoint push it out to the graph.
			if (dataPoint[this.MEM_SERIES].length){
					var dp = dataPoint[this.MEM_SERIES];
					s[this.MEM_SERIES].push((df.reduce(dp, function(a, b){return a+b}) / dp.length)/1024);
					dp = dataPoint[this.CPU_SERIES];
					s[this.CPU_SERIES].push(df.reduce(dp, function(a, b){return a+b}) / dp.length);
			}
			this.lastTimestampInSeries = now;
//console.log("END: this.lastTimestampInSeries=", this.lastTimestampInSeries);
//console.log("do draw", dojo.toJson(s));
			
//console.log(s[this.MEM_SERIES].length, dojo.toJson(s[this.MEM_SERIES]));
			// Limit the number of dataPoints to this.CHART_WIDTH
			if (s[this.MEM_SERIES].length > this.CHART_WIDTH){
				var sliceAt = s[this.MEM_SERIES].length - this.CHART_WIDTH;
//console.log("sliceAt=", sliceAt);
				s[this.MEM_SERIES] = s[this.MEM_SERIES].slice(sliceAt);
				s[this.CPU_SERIES] = s[this.CPU_SERIES].slice(sliceAt);
			}
			
			// Draw the series.
			this.chart.updateSeries("memory", s[this.MEM_SERIES]);
			this.chart.updateSeries("cpu", s[this.CPU_SERIES]);
			// Adjust the y axis, which shows the memory consumption.
			//var max = 0;
			//for (var i=0; i<s[MEM_SERIES].length; i++){
			//    console.log("max=", 123);
			//	max = max>s[MEM_SERIES][i] ? max : s[MEM_SERIES][i];
			//}
			//console.log("max=", max);
			//
			//var pow = Math.pow(10, String(max).length-1);
			//max = Math.ceil(max / pow) * pow;
			//console.log("max=", max);
			//chart.axes.y.destroy();
			//var kwargs = {vertical: true, min:0, max:parseInt(max), majorTickStep: 50, minorTickStep: 10};
			//chart.addAxis("y", {vertical: true, min:0, max:parseInt(max), majorTickStep: 50, minorTickStep: 10});
			//var xs = new dojox.charting.axis2d.Default(chart, kwargs);
			//xs.name = "y"; xs.dirty=true;
			//chart.dirty = true;
			//chart.axes.y = xs;
			
//console.log(5);
			this.chart.render();
//console.log(6);
		},
		
		resize: function(width, height){
			
		}
	}
);
